home *** CD-ROM | disk | FTP | other *** search
/ The World's Largest Collection of Windows Software / The World's Largest Collection of Windows Software - Disc 1.iso / connect / _j2 / wvnsc926 / wvpath.c < prev    next >
C/C++ Source or Header  |  1994-09-18  |  27KB  |  822 lines

  1. /*
  2.  * wvpath.c
  3.  *
  4.  * based on ddlist example is MSDN (Copyright (c)1992 Kraig Brockschmidt)
  5.  *
  6.  * John S. Cooper
  7.  * 9/10/94
  8.  */
  9.  
  10. #include <windows.h>
  11. #include <windowsx.h>
  12. #include "wvglob.h"
  13. #include "winvn.h"
  14. #pragma hdrstop
  15. #include <dos.h>
  16. #include <io.h>            // for _access
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <direct.h>
  20. #include <string.h>
  21.  
  22. /* forward declarations */
  23.  
  24. void DriveListInitialize(HWND, HWND);
  25. UINT DriveType(UINT);
  26. void DirectoryListInitialize(HWND, HWND, LPSTR);
  27. void DriveDirDrawItem(LPDRAWITEMSTRUCT, BOOL);
  28. void TransparentBlt(HDC, UINT, UINT, HBITMAP, COLORREF);
  29.  
  30. //Special ROP code for TransparentBlt.
  31. #define ROP_DSPDxax  0x00E20746
  32.  
  33. /*
  34.  * DriveListInitialize
  35.  *
  36.  * Purpose:
  37.  *  Resets and fills the given combobox with a list of current
  38.  *  drives.  The type of drive is stored with the item data.
  39.  *
  40.  * Parameters:
  41.  *  hList           HWND of the combobox to fill.
  42.  *  hTempList       HWND to use for finding drives.
  43.  *
  44.  * Return Value:
  45.  *  None
  46.  */
  47.  
  48. void DriveListInitialize(HWND hList, HWND hTempList)
  49.     {
  50.     struct find_t   fi;
  51.     char            ch;
  52.     UINT            i, iItem;
  53.     UINT            cch, cItems;
  54.     UINT            iDrive, iType;
  55.     UINT            iCurDrive;
  56.     char            szDrive[10];
  57.     char            szNet[64];
  58.     char            szItem[26];
  59.  
  60.     if (NULL==hList)
  61.         return;
  62.  
  63.     //Clear out all the lists.
  64.     SendMessage(hList,     CB_RESETCONTENT, 0, 0L);
  65.     SendMessage(hTempList, LB_RESETCONTENT, 0, 0L);
  66.  
  67.     //Get available drive letters in the temp list
  68.     SendMessage(hTempList, LB_DIR, DDL_DRIVES | DDL_EXCLUSIVE, (LONG)(LPSTR)"*");
  69.  
  70.     iCurDrive=_getdrive()-1;       //Fix for zero-based drive indexing
  71.  
  72.     /*
  73.      * Walk through the list of drives, parsing off the "[-" and "-]"
  74.      * For each drive letter parsed, add a string to the combobox
  75.      * composed of the drive letter and the volume label.  We then
  76.      * determine the drive type and add that information as the item data.
  77.      */
  78.     cItems=(int)SendMessage(hTempList, LB_GETCOUNT, 0, 0L);
  79.  
  80.     for (i=0; i<cItems;  i++)
  81.         {
  82.         SendMessage(hTempList, LB_GETTEXT, i, (LONG)(LPSTR)szDrive);
  83.  
  84.         //Insure lowercase drive letters
  85.         AnsiLower(szDrive);
  86.         iDrive=szDrive[2]-'a';
  87.         iType=DriveType(iDrive);        //See Below
  88.  
  89.         if (iType < 2)                  //Skip non-existent drive B's
  90.             continue;
  91.  
  92.         //Start the item string with the drive letter, color, and two spaces
  93.         wsprintf(szItem, "%c%s", szDrive[2], (LPSTR)":  ");
  94.  
  95.         /*
  96.          * For fixed or ram disks, append the volume label which we find
  97.          * using _dos_findfirst and attribute _A_VOLID.
  98.          */
  99.         if (DRIVE_FIXED==iType || DRIVE_RAM==iType)
  100.             {
  101.             wsprintf(szDrive, "%c:\\*.*", szDrive[2]);
  102.  
  103.             if (0==_dos_findfirst(szDrive, _A_VOLID, &fi))
  104.                 {
  105.                 //Convert volume to lowercase and strip any . in the name.
  106.                 AnsiLower(fi.name);
  107.  
  108.                 //If a period exists, it has to be in position 8, so clear it.
  109.                 ch=fi.name[8];
  110.                 fi.name[8]=0;
  111.                 lstrcat(szItem, fi.name);
  112.  
  113.                 //If we did have a broken volume name, append the last 3 chars
  114.                 if ('.'==ch)
  115.                     lstrcat(szItem, &fi.name[9]);
  116.                 }
  117.             }
  118.  
  119.         //For network drives, go grab the \\server\share for it.
  120.         if (DRIVE_REMOTE==iType)
  121.             {
  122.             szNet[0]=0;
  123.             cch=sizeof(szNet);
  124.  
  125.             wsprintf(szDrive, "%c:", szDrive[2]);
  126.             AnsiUpper(szDrive);
  127.  
  128.             WNetGetConnection((LPSTR)szDrive, (LPSTR)szNet, &cch);
  129.             AnsiLower(szNet);
  130.  
  131.             lstrcat(szItem, szNet);
  132.             }
  133.  
  134.         iItem=(int)SendMessage(hList, CB_ADDSTRING, 0, (LONG)(LPSTR)szItem);
  135.         SendMessage(hList, CB_SETITEMDATA, iItem, MAKELONG(iDrive, iType));
  136.  
  137.         if (iDrive==iCurDrive)
  138.             SendMessage(hList, CB_SETCURSEL, iItem, 0L);
  139.         }
  140.  
  141.     return;
  142.     }
  143.  
  144. /*
  145.  * DriveType
  146.  *
  147.  * Purpose:
  148.  *  Augments the Windows API GetDriveType with a call to the CD-ROM
  149.  *  extensions to determine if a drive is a floppy, hard disk, CD-ROM,
  150.  *  RAM-drive, or networked  drive.
  151.  *
  152.  * Parameters:
  153.  *  iDrive          UINT containing the zero-based drive index
  154.  *
  155.  * Return Value:
  156.  *  UINT            One of the following values describing the drive:
  157.  *                  DRIVE_FLOPPY, DRIVE_HARD, DRIVE_CDROM, DRIVE_RAM,
  158.  *                  DRIVE_NETWORK.
  159.  */
  160.  
  161. UINT DriveType(UINT iDrive)
  162.     {
  163.     int     iType;
  164.     BOOL    fCDROM=FALSE;
  165.     BOOL    fRAM=FALSE;
  166.  
  167.  
  168.     //Validate possible drive indices
  169.     if (0 > iDrive  || 25 < iDrive)
  170.         return 0xFFFF;
  171.  
  172.     iType=GetDriveType(iDrive);
  173.  
  174.     /*
  175.      * Under Windows NT, GetDriveType returns complete information
  176.      * not provided under Windows 3.x which we now get through other
  177.      * means.
  178.      */
  179.    #ifdef WIN32
  180.     return iType;
  181.    #else
  182.     //Check for CDROM on FIXED and REMOTE drives only
  183.     if (DRIVE_FIXED==iType || DRIVE_REMOTE==iType)
  184.         {
  185.         _asm
  186.             {
  187.             mov     ax,1500h        //Check if MSCDEX exists
  188.             xor     bx,bx
  189.             int     2fh
  190.  
  191.             or      bx,bx           //BX unchanged if MSCDEX is not around
  192.             jz      CheckRAMDrive   //No?  Go check for RAM drive.
  193.  
  194.             mov     ax,150Bh        //Check if drive is using CD driver
  195.             mov     cx,iDrive
  196.             int     2fh
  197.  
  198.             mov     fCDROM,ax       //AX if the CD-ROM flag
  199.             or      ax,ax
  200.             jnz     Exit            //Leave if we found a CD-ROM drive.
  201.  
  202.             CheckRAMDrive:
  203.             }
  204.         }
  205.  
  206.     //Check for RAM drives on FIXED disks only.
  207.     if (DRIVE_FIXED==iType)
  208.         {
  209.         /*
  210.          * Check for RAM drive is done by reading the boot sector and
  211.          * looking at the number of FATs.  Ramdisks only have 1 while
  212.          * all others have 2.
  213.          */
  214.         _asm
  215.             {
  216.             push    ds
  217.  
  218.             mov     bx,ss
  219.             mov     ds,bx
  220.  
  221.             sub     sp,0200h            //Reserve 512 bytes to read a sector
  222.             mov     bx,sp               //and point BX there.
  223.  
  224.             mov     ax,iDrive           //Read the boot sector of the drive
  225.             mov     cx,1
  226.             xor     dx,dx
  227.  
  228.             int     25h
  229.             add     sp,2                //Int 25h requires our stack cleanup.
  230.             jc      DriveNotRAM
  231.  
  232.             mov     bx,sp
  233.             cmp     ss:[bx+15h],0f8h    //Reverify fixed disk
  234.             jne     DriveNotRAM
  235.             cmp     ss:[bx+10h],1       //Check if there's only one FATs
  236.             jne     DriveNotRAM
  237.             mov     fRAM,1
  238.  
  239.             DriveNotRAM:
  240.             add     sp,0200h
  241.             pop     ds
  242.  
  243.             Exit:
  244.             //Leave fRAM untouched  it's FALSE by default.
  245.             }
  246.         }
  247.  
  248.     /*
  249.      * If either CD-ROM or RAM drive flags are set, return privately
  250.      * defined flags for them (outside of Win32).  Otherwise return
  251.      * the type given from GetDriveType.
  252.      */
  253.  
  254.     if (fCDROM)
  255.         return DRIVE_CDROM;
  256.  
  257.     if (fRAM)
  258.         return DRIVE_RAM;
  259.  
  260.     //Drive B on a one drive system returns < 2 from GetDriveType.
  261.     return iType;
  262.    #endif
  263.     }
  264.  
  265. /*
  266.  * DirectoryListInitialize
  267.  *
  268.  * Purpose:
  269.  *  Initializes strings in a listbox given a directory path.  The first
  270.  *  string in the listbox is the drive letter.  The remaining items are
  271.  *  each directory in the path completed with a listing of all sub-
  272.  *  directories under the last directory in the path.
  273.  *
  274.  * Parameters:
  275.  *  hList           HWND of the listbox to fill.
  276.  *  hTempList       HWND of a listbox to use for  directory enumerations.
  277.  *  pszDir          LPSTR of the path to use in initialization assumed
  278.  *                  to be at least _MAX_DIR long.
  279.  *
  280.  * Return Value:
  281.  *  None
  282.  */
  283.  
  284. void DirectoryListInitialize(HWND hList, HWND hTempList, LPSTR pszDir)
  285.     {
  286.     LPSTR       psz, pszLast;
  287.     char        ch;
  288.     char        szDir[_MAX_DIR];
  289.     UINT        cch, cItems;
  290.     UINT        i, iItem, iIndent;
  291.     BOOL        fFirst=TRUE;
  292.  
  293.     if (NULL==hList || NULL==pszDir)
  294.         return;
  295.  
  296.     //If the path ends in a \, strip the '\'
  297.     cch=lstrlen(pszDir);
  298.  
  299.     if ('\\'==pszDir[cch-1])
  300.         pszDir[cch-1]=0;
  301.  
  302.     //Clear out all the lists.
  303.     SendMessage(hList,     WM_SETREDRAW,    FALSE, 0L);
  304.     SendMessage(hList,     LB_RESETCONTENT, 0,     0L);
  305.     SendMessage(hTempList, LB_RESETCONTENT, 0,     0L);
  306.  
  307.     /*
  308.      * Walk through the path one \ at a time.  At each one found,
  309.      * we add the string composed of the characters between it and
  310.      * the last \ found.  We also make sure everything is lower case.
  311.      */
  312.  
  313.     pszLast=AnsiLower(pszDir);
  314.  
  315.     //Save this for changing directories
  316.     SetWindowText(hList, pszDir);
  317.  
  318.     //Save the directory appended with \*.*
  319.     wsprintf(szDir, "%s\\*.*", pszDir);
  320.  
  321.     while (TRUE)
  322.         {
  323.         psz=_fstrchr(pszLast, '\\');
  324.  
  325.         if (NULL!=psz)
  326.             {
  327.             /*
  328.              * Save the character here so we can NULL terminate.  If this
  329.              * if the first entry, it's a drive root, so keep the \
  330.              */
  331.  
  332.             if (fFirst)
  333.                 ch=*(++psz);
  334.             else
  335.                 ch=*psz;
  336.  
  337.             *psz=0;
  338.             }
  339.         else
  340.             {
  341.             //If we're looking at a drive only, then append a backslash
  342.             if (pszLast==pszDir && fFirst)
  343.                 lstrcat(pszLast, "\\");
  344.             }
  345.  
  346.         //Add the drive string--includes the last one where psz==NULL
  347.         iItem=(UINT)SendMessage(hList, LB_ADDSTRING, 0, (LONG)pszLast);
  348.  
  349.         /*
  350.          * The item data here has in the HIWORD the bitmap to use for
  351.          * the item with the LOWORD containing the indentation.  The
  352.          * bitmap is IDB_FOLDEROPEN for anything above the current
  353.          * directory (that is, c:\foo is above than c:\foo\bar),
  354.          * IDB_FOLDERCLOSED for anything below the current, and
  355.          * IDB_FOLDEROPENSELECT for the current directory.
  356.          */
  357.  
  358.         i=(NULL!=psz) ? IDB_FOLDEROPEN : IDB_FOLDEROPENSELECT;
  359.         SendMessage(hList, LB_SETITEMDATA, iItem, MAKELONG(iItem, i));
  360.  
  361.         if (NULL==psz)
  362.             break;
  363.  
  364.         //Restore last character.
  365.         *psz=ch;
  366.         psz+=(fFirst) ? 0 : 1;
  367.  
  368.         fFirst=FALSE;
  369.         pszLast=psz;
  370.         }
  371.  
  372.  
  373.     /*
  374.      * Now that we have the path in, enumerate the subdirectories here
  375.      * and place them in the list at the indentation iItem+1 since iItem
  376.      * was the index of the last item in the path added to the list.
  377.      *
  378.      * To enumerate the directories, we send LB_DIR to an alternate
  379.      * listbox.  On return, we have to parse off the brackets around
  380.      * those directory names before bringing them into this listbox.
  381.      */
  382.  
  383.     iIndent=iItem+1;
  384.  
  385.     //Get available directories; szDir is pszDir\*.*
  386.     SendMessage(hTempList, LB_DIR, DDL_DIRECTORY | DDL_EXCLUSIVE
  387.                 , (LONG)(LPSTR)szDir);
  388.  
  389.     cItems=(int)SendMessage(hTempList, LB_GETCOUNT, 0, 0L);
  390.  
  391.     for (i=0; i<cItems; i++)
  392.         {
  393.         cch=(UINT)SendMessage(hTempList, LB_GETTEXT, i, (LONG)(LPSTR)szDir);
  394.  
  395.         //Skip directories beginning with . (skipping . and ..)
  396.         if ('.'==szDir[1])
  397.             continue;
  398.  
  399.         //Remove the ending ']'
  400.         szDir[cch-1]=0;
  401.  
  402.         //Add the string to the real directory list.
  403.         iItem=(UINT)SendMessage(hList, LB_ADDSTRING, 0
  404.                                 , (LONG)(LPSTR)(szDir+1));
  405.         SendMessage(hList, LB_SETITEMDATA, iItem
  406.                     , MAKELONG(iIndent, IDB_FOLDERCLOSED));
  407.         }
  408.  
  409.     //Force a listbox repaint.
  410.     SendMessage(hList, WM_SETREDRAW, TRUE, 0L);
  411.     InvalidateRect(hList, NULL, TRUE);
  412.  
  413.     /*
  414.      * If there's a vertical scrollbar, then we've added more items than
  415.      * are visible at once.  To meet the UI specifications, we're supposed
  416.      * to make the next directory up the top visible one.
  417.      */
  418.     GetScrollRange(hList, SB_VERT, (LPINT)&i, (LPINT)&iItem);
  419.  
  420.     if (!(0==i && 0==iItem))
  421.         SendMessage(hList, LB_SETTOPINDEX, max((int)(iIndent-2), 0), 0L);
  422.  
  423.     //Last thing is to set the current directory as the selection
  424.     SendMessage(hList, LB_SETCURSEL, iIndent-1, 0L);
  425.     return;
  426.     }
  427.  
  428. /*
  429.  * DriveDirDrawItem
  430.  *
  431.  * Purpose:
  432.  *  Handles WM_DRAWITEM for both drive and directory listboxes.
  433.  *
  434.  * Parameters:
  435.  *  pDI             LPDRAWITEMSTRUCT passed with the WM_DRAWITEM message.
  436.  *  fDrive          BOOL TRUE to draw a drive, FALSE to draw directory.
  437.  *
  438.  * Return Value:
  439.  *  None
  440.  */
  441.  
  442. void DriveDirDrawItem(LPDRAWITEMSTRUCT pDI, BOOL fDrive)
  443.     {
  444.     char        szItem[40];
  445.     int         iType=0;
  446.     int         iIndent=0;
  447.     UINT        uMsg;
  448.     DWORD       dw;
  449.     BITMAP      bm;
  450.     COLORREF    crText, crBack;
  451.     HBITMAP     hBmp;
  452.  
  453.     if ((int)pDI->itemID < 0)
  454.         return;
  455.  
  456.     if (fDrive)
  457.         dw=SendMessage(pDI->hwndItem, CB_GETITEMDATA, pDI->itemID, 0L);
  458.  
  459.     //Get the text string for this item (controls have different messages)
  460.     uMsg=(fDrive) ? CB_GETLBTEXT : LB_GETTEXT;
  461.     SendMessage(pDI->hwndItem, uMsg, pDI->itemID, (LONG)(LPSTR)szItem);
  462.  
  463.     if ((ODA_DRAWENTIRE | ODA_SELECT) & pDI->itemAction)
  464.         {
  465.         if (ODS_SELECTED & pDI->itemState)
  466.             {
  467.             //Select the appropriate text colors
  468.             crText=SetTextColor(pDI->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  469.             crBack=SetBkColor(pDI->hDC, GetSysColor(COLOR_HIGHLIGHT));
  470.             }
  471.  
  472.         /*
  473.          * References to the two bitmap arrays here are the only external
  474.          * dependencies of this code.  To keep it simple, we didn't use
  475.          * a more complex scheme like putting all the images into one bitmap.
  476.          */
  477.         if (fDrive)
  478.             {
  479.             //For drives, get the type, which determines the bitmap.
  480.             iType=(int)HIWORD(dw);
  481.             hBmp=DiskBitmaps[iType-IDB_DRIVEMIN];
  482.             }
  483.         else
  484.             {
  485.             //For directories, indentation level is 4 pixels per indent.
  486.             iIndent=4*(1+LOWORD(pDI->itemData));
  487.             hBmp=FolderBitmaps[HIWORD(pDI->itemData)-IDB_FOLDERMIN];
  488.             }
  489.  
  490.         GetObject(hBmp, sizeof(bm), &bm);
  491.  
  492.         /*
  493.          * Paint the text and the rectangle in whatever colors.  If
  494.          * we're drawing drives, iIndent is zero so it's ineffective.
  495.          */
  496.         ExtTextOut(pDI->hDC, pDI->rcItem.left+bm.bmWidth+4+iIndent
  497.                    , pDI->rcItem.top, ETO_OPAQUE, &pDI->rcItem, szItem
  498.                    , lstrlen(szItem), (LPINT)NULL);
  499.  
  500.  
  501.         //Go draw the bitmap we want.
  502.         TransparentBlt(pDI->hDC, pDI->rcItem.left+iIndent
  503.                        , pDI->rcItem.top, hBmp, RGB(0,0,255));
  504.  
  505.         //Restore original colors if we changed them above.
  506.         if (ODS_SELECTED & pDI->itemState)
  507.             {
  508.             SetTextColor(pDI->hDC, crText);
  509.             SetBkColor(pDI->hDC,   crBack);
  510.             }
  511.         }
  512.  
  513.     if ((ODA_FOCUS & pDI->itemAction) || (ODS_FOCUS & pDI->itemState))
  514.         DrawFocusRect(pDI->hDC, &pDI->rcItem);
  515.  
  516.     return;
  517.     }
  518.  
  519. /*
  520.  * TransparentBlt
  521.  *
  522.  *  Given a DC, a bitmap, and a color to assume as transparent in that
  523.  *  bitmap, BitBlts the bitmap to the DC letting the existing background
  524.  *  show in place of the transparent color.
  525.  *
  526.  * Parameters:
  527.  *  hDC             HDC on which to draw.
  528.  *  x, y            UINT location at which to draw the bitmap
  529.  *  hBmp            HBITMIP to draw
  530.  *  cr              COLORREF to consider as transparent.
  531.  */
  532.  
  533. void TransparentBlt(HDC hDC, UINT x, UINT y, HBITMAP hBmp, COLORREF cr)
  534.     {
  535.     HDC         hDCSrc, hDCMid, hMemDC;
  536.     HBITMAP     hBmpMono, hBmpT;
  537.     HBRUSH      hBr, hBrT;
  538.     COLORREF    crBack, crText;
  539.     BITMAP      bm;
  540.  
  541.     if (NULL==hBmp)
  542.         return;
  543.  
  544.     GetObject(hBmp, sizeof(bm), &bm);
  545.  
  546.     //Get three intermediate DC's
  547.     hDCSrc=CreateCompatibleDC(hDC);
  548.     hDCMid=CreateCompatibleDC(hDC);
  549.     hMemDC=CreateCompatibleDC(hDC);
  550.  
  551.     SelectObject(hDCSrc, hBmp);
  552.  
  553.     //Create a monochrome bitmap for masking
  554.     hBmpMono=CreateCompatibleBitmap(hDCMid, bm.bmWidth, bm.bmHeight);
  555.     SelectObject(hDCMid, hBmpMono);
  556.  
  557.     //Create a middle bitmap
  558.     hBmpT=CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
  559.     SelectObject(hMemDC, hBmpT);
  560.  
  561.  
  562.     //Create a monochrome mask where we have 0's in the image, 1's elsewhere.
  563.     crBack=SetBkColor(hDCSrc, cr);
  564.     BitBlt(hDCMid, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0, SRCCOPY);
  565.     SetBkColor(hDCSrc, crBack);
  566.  
  567.     //Put the unmodified image in the temporary bitmap
  568.     BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0, SRCCOPY);
  569.  
  570.     //Create an select a brush of the background color
  571.     hBr=CreateSolidBrush(GetBkColor(hDC));
  572.     hBrT=SelectObject(hMemDC, hBr);
  573.  
  574.     //Force conversion of the monochrome to stay black and white.
  575.     crText=SetTextColor(hMemDC, 0L);
  576.     crBack=SetBkColor(hMemDC, RGB(255, 255, 255));
  577.  
  578.     /*
  579.      * Where the monochrome mask is 1, Blt the brush; where the mono mask
  580.      * is 0, leave the destination untouches.  This results in painting
  581.      * around the image with the background brush.  We do this first
  582.      * in the temporary bitmap, then put the whole thing to the screen.
  583.      */
  584.     BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCMid, 0, 0, ROP_DSPDxax);
  585.     BitBlt(hDC,    x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY);
  586.  
  587.  
  588.     SetTextColor(hMemDC, crText);
  589.     SetBkColor(hMemDC, crBack);
  590.  
  591.     SelectObject(hMemDC, hBrT);
  592.     DeleteObject(hBr);
  593.  
  594.     DeleteDC(hMemDC);
  595.     DeleteDC(hDCSrc);
  596.     DeleteDC(hDCMid);
  597.     DeleteObject(hBmpT);
  598.     DeleteObject(hBmpMono);
  599.  
  600.     return;
  601.     }
  602.  
  603. /*
  604.  * WinVnSelectPathDialogDlg
  605.  *
  606.  *  Handles the dialog that displays a drive and directory owner-draw
  607.  *  combobox and listbox, respectiviely.  This procedure handles only
  608.  *  the WM_INITDIALOG and WM_DRAWITEM messages,dispatching them to
  609.  *  alternate functions that handle each message for each list.
  610.  *
  611.  */
  612.  
  613. BOOL FAR PASCAL WinVnSelectPathDlg(HWND hDlg,unsigned iMessage,WPARAM wParam,LPARAM lParam)
  614.     {
  615.  
  616.     char cwd[_MAX_PATH];
  617.  
  618.     WORD            wID;
  619.     WORD            wCode;
  620.     HWND            hWndMsg;
  621.  
  622.     hWndMsg=(HWND)(UINT)lParam;
  623.     wID=LOWORD(wParam);
  624.     #ifdef WIN32
  625.         wCode=HIWORD(wParam);
  626.     #else
  627.         wCode=HIWORD(lParam);
  628.     #endif
  629.  
  630.     switch (iMessage)
  631.         {
  632.         case WM_INITDIALOG:
  633.             ShowWindow(hDlg, SW_SHOW);
  634.             UpdateWindow(hDlg);
  635.  
  636.             DriveListInitialize(GetDlgItem(hDlg, ID_DRIVELIST), GetDlgItem(hDlg, ID_TEMPLIST));
  637.  
  638.             if (lParam    && _access((char *)lParam, 0) >= 0) {
  639.                 strcpy (cwd, (char *)lParam);
  640.                 _chdir(cwd);
  641.             } else
  642.                    _getcwd(cwd, _MAX_PATH);
  643.             
  644.             DirectoryListInitialize(GetDlgItem(hDlg, ID_DIRECTORYLIST), GetDlgItem(hDlg, ID_TEMPLIST), cwd);
  645.             return TRUE;
  646.  
  647.         case WM_MEASUREITEM:
  648.             {
  649.             static int              cyItem=-1;      //Height of a listbox item
  650.             LPMEASUREITEMSTRUCT     pMI;
  651.  
  652.             pMI=(LPMEASUREITEMSTRUCT)lParam;
  653.  
  654.             if (-1==cyItem)
  655.                 {
  656.                 HFONT       hFont;
  657.                 HDC         hDC;
  658.                 TEXTMETRIC  tm;
  659.                 BITMAP      bm;
  660.  
  661.                 /*
  662.                  * Attempt to get the font of the dialog. However,
  663.                  * on the first attempt in the life of the dialog,
  664.                  * this could fail; in that case use the system font.
  665.                  */
  666.                 hFont=(HANDLE)(UINT)SendMessage(hDlg, WM_GETFONT, 0, 0L);
  667.  
  668.                 if (NULL==hFont)
  669.                     hFont=GetStockObject(SYSTEM_FONT);
  670.  
  671.                 hDC=GetDC(hDlg);
  672.                 hFont=SelectObject(hDC, hFont);
  673.  
  674.                 /*
  675.                  * Item height is the maximum of the font height and the
  676.                  * bitmap height.  We know that all bitmaps are the same
  677.                  * size, so we just get information for one of them.
  678.                  */
  679.                 GetTextMetrics(hDC, &tm);
  680.                 GetObject(FolderBitmaps[0], sizeof(bm), &bm);
  681.                 cyItem=max(bm.bmHeight, tm.tmHeight);
  682.  
  683.                 ReleaseDC(hDlg, hDC);
  684.                 }
  685.  
  686.             pMI->itemHeight=cyItem;
  687.             }
  688.             break;
  689.  
  690.  
  691.         case WM_DRAWITEM:
  692.             //Go draw the appropriate item and bitmap.
  693.             DriveDirDrawItem((LPDRAWITEMSTRUCT)lParam, (ID_DRIVELIST==wID));
  694.  
  695.             //Prevent default actions in listboxes (drawing focus rect)
  696.             return TRUE;
  697.  
  698.  
  699.         case WM_COMMAND:
  700.             switch (wID)
  701.                 {
  702.                 case ID_DIRECTORYLIST:
  703.                     if (LBN_DBLCLK==wCode)
  704.                         {
  705.                         UINT        i;
  706.                         DWORD       dw;
  707.                         char        szDir[_MAX_PATH];
  708.                         LPSTR       psz;
  709.  
  710.                         /*
  711.                          * On double-click, change directory and reinit the
  712.                          * listbox.  But all we stored in the string was
  713.                          * the directory's single name, so we use the bitmap
  714.                          * type to tell if we're below the current directory
  715.                          * (in which case we just chdir to our name) or above
  716.                          * (in which case we prepend "..\"'s as necessary.
  717.                          */
  718.                         i=(UINT)SendMessage(hWndMsg, LB_GETCURSEL, 0, 0L);
  719.                         dw=SendMessage(hWndMsg, LB_GETITEMDATA, i, 0L);
  720.  
  721.                         /*
  722.                          * If out bitmap is IDB_FOLDERCLOSED or the root,
  723.                          * then just .  If we're IDB_FOLDEROPENSELECT,
  724.                          * don't do anything.  If we're IDB_FOLDEROPEN then
  725.                          * we get the full current path and truncate it
  726.                          * after the directory to which we're switching.
  727.                          */
  728.                         if (IDB_FOLDEROPENSELECT==HIWORD(dw))
  729.                             break;
  730.  
  731.                         //Get get the directory for sub-directory changes.
  732.                         SendMessage(hWndMsg, LB_GETTEXT, i, (LONG)(LPSTR)cwd);
  733.  
  734.                         if (IDB_FOLDEROPEN==HIWORD(dw) && 0!=i)
  735.                             {
  736.                             //Get the current path and find us in this path
  737.                             GetWindowText(hWndMsg, szDir, sizeof(szDir));
  738.                             psz=_fstrstr(szDir, cwd);
  739.  
  740.                             //Null terminate right after us.
  741.                             *(psz+lstrlen(cwd))=0;
  742.  
  743.                             //Get this new directory in the right place
  744.                             lstrcpy(cwd, szDir);
  745.                             }
  746.  
  747.                         //chdir has a nice way of validating for us.
  748.                         if (0==_chdir(cwd))
  749.                             {
  750.                             //Get the new full path.
  751.                             _getcwd(cwd, _MAX_PATH);
  752.  
  753.                             DirectoryListInitialize(hWndMsg
  754.                                 , GetDlgItem(hDlg, ID_TEMPLIST), cwd);
  755.                             }
  756.                         }
  757.                     break;
  758.  
  759.  
  760.                 case ID_DRIVELIST:
  761.                     if (CBN_SELCHANGE==wCode)
  762.                         {
  763.                         UINT        i, iCurDrive;
  764.                         char        szDrive[18]; //Enough for drive:volume
  765.  
  766.                         //Get the first letter in the current selection
  767.                         i=(UINT)SendMessage(hWndMsg, CB_GETCURSEL, 0, 0L);
  768.                         SendMessage(hWndMsg, CB_GETLBTEXT
  769.                                     , i, (LONG)(LPSTR)szDrive);
  770.  
  771.                         iCurDrive=_getdrive();  //Save in case of restore
  772.  
  773.                         /*
  774.                          * Attempt to set the drive and get the current
  775.                          * directory on it.  Both must work for the change
  776.                          * to be certain.  If we are certain, reinitialize
  777.                          * the directories.  Note that we depend on drives
  778.                          * stored as lower case in the combobox.
  779.                          */
  780.  
  781.                         if (0==_chdrive((int)(szDrive[0]-'a'+1))
  782.                             && NULL!=_getcwd(cwd, _MAX_PATH))
  783.                             {
  784.                             DirectoryListInitialize(
  785.                                 GetDlgItem(hDlg, ID_DIRECTORYLIST),
  786.                                 GetDlgItem(hDlg, ID_TEMPLIST), cwd);
  787.  
  788.                             //Insure that the root is visible (UI guideline)
  789.                             SendDlgItemMessage(hDlg, ID_DIRECTORYLIST
  790.                                                , LB_SETTOPINDEX, 0, 0L);
  791.  
  792.                             break;
  793.                             }
  794.  
  795.                         //Changing drives failed so restore drive and selection
  796.                         _chdrive((int)iCurDrive);
  797.  
  798.                         wsprintf(szDrive, "%c:", (char)(iCurDrive+'a'-1));
  799.                         i=(UINT)SendMessage(hWndMsg, CB_SELECTSTRING
  800.                                             , (WPARAM)-1, (LONG)(LPSTR)szDrive);
  801.                         }
  802.  
  803.                     break;
  804.  
  805.                 case IDOK:
  806.                     _getcwd(DialogString, MAXINTERNALLINE);
  807.                     EndDialog(hDlg, TRUE);
  808.                     break;
  809.                   case IDCANCEL:
  810.                     EndDialog (hDlg, FALSE);
  811.                     break;
  812.                 }
  813.             break;
  814.  
  815.         default:
  816.             break;
  817.         }
  818.  
  819.     return FALSE;
  820.     }
  821.  
  822.